/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "CertMgr.h"
#include <fstream>
#include "log/Log.h"
#include "PluginUtilities.h"
#include "common/JsonHelper.h"

namespace {
    constexpr auto MODULE = "CertMgr";
    const std::string OPT_LOG_PATH = "/opt/logpath";
    const std::string CRET_PATH = "/certification.pem";
    const std::string CRL_PATH = "/crl.pem";
}
using namespace PluginUtils;

CertMgr::~CertMgr()
{
    Module::CleanMemoryPwd(m_authExt.certification);
    Module::CleanMemoryPwd(m_authExt.revocationList);
}

bool CertMgr::InitInfo(const AppProtect::ApplicationEnvironment& protectEnv, const std::string& jobId)
{
    m_rootPath = OPT_LOG_PATH + "/ca_" + jobId;
    m_certPath = OPT_LOG_PATH + "/ca_" + jobId + CRET_PATH;
    m_crlPath = OPT_LOG_PATH + "/ca_" + jobId + CRL_PATH;
    if (!Module::JsonHelper::JsonStringToStruct(protectEnv.extendInfo, m_protectEnvExtendInfo)) {
        HCP_Log(ERR, MODULE) << "Failed to parse protctEnv extendInfo json to struct" << HCPENDLOG;
        return false;
    }
    if (m_protectEnvExtendInfo.verifyStatus != "1") {  // "1"：证书校验；"0"：不校验
        return true;
    }
    m_verifyStatus = true;
    if (!Module::JsonHelper::JsonStringToStruct(protectEnv.auth.extendInfo, m_authExt)) {
        HCP_Log(ERR, MODULE) << "Failed to parse protctEnv auth extendInfo json to struct" << HCPENDLOG;
        return false;
    }
    return true;
}

std::string CertMgr::GetCertPath() const
{
    return m_certPath;
}

std::string CertMgr::GetCrlPath() const
{
    return m_crlPath;
}

bool CertMgr::IsVerify() const
{
    return m_verifyStatus;
}

bool CertMgr::SaveFile(const std::string &filePath, const std::string &content, int cycleNums) const
{
    int retryTimes = 0;
    // 将content参数内容写入文件，尝试三次未成功后返回失败
    while (retryTimes < cycleNums) {
        HCP_Log(INFO, MODULE) << "Try to save file " << (retryTimes + 1) << "time" << HCPENDLOG;
        std::ofstream writer;
        writer.open(filePath.c_str(), std::ios::binary);
        if (writer) {
            writer.write(content.c_str(), content.size());
            writer.close();
            return true;
        }
        retryTimes++;
    }
    HCP_Log(ERR, MODULE) << "Save file failed, filename: " << filePath << HCPENDLOG;
    return false;
}

bool CertMgr::IncludeRevocationList() const
{
    HCP_Log(INFO, MODULE) << "Check whether the revocation list are included." << HCPENDLOG;
    return !m_authExt.revocationList.empty();
}

/* 检查job中是否包含证书和吊销列表信息，如果有则将信息落盘 */
bool CertMgr::FlushCertificationToDisk() const
{
    // 如果证书根目录存在，说明前置任务已经完成落盘
    if (IsDirExist(m_rootPath)) {
        HCP_Log(INFO, MODULE) << "The certification already exists." << HCPENDLOG;
        return true;
    }
    // 首先创建根目录rootPath
    if (!CreateDirectory(m_rootPath)) {
        HCP_Log(ERR, MODULE) << "Failed to create temp CA path" << HCPENDLOG;
        return false;
    }

    HCP_Log(INFO, MODULE) << "Start to save cert" << HCPENDLOG;
    return SaveFile(m_certPath, m_authExt.certification);
}

bool CertMgr::FlushRevocationListToDisk() const
{
    if (IsFileExist(m_crlPath)) {
        HCP_Log(INFO, MODULE) << "The CRL already exists." << HCPENDLOG;
        return true;
    }
    HCP_Log(INFO, MODULE) << "Start to save CRL" << HCPENDLOG;
    return SaveFile(m_crlPath, m_authExt.revocationList);
}

bool CertMgr::RemoveCertAndRevocationListFromDisk() const
{
    if (RemoveDirectory(m_rootPath)) {
        HCP_Log(INFO, MODULE) << "Remove Certification and CRL success" << HCPENDLOG;
        return true;
    }
    HCP_Log(ERR, MODULE) << "Remove Certification and CRL failed" << HCPENDLOG;
    return false;
}
